﻿using SimpleCompiler;
// See https://aka.ms/new-console-template for more information

internal class TestCase
{

    /// <summary>
    /// int a = 1; int b = 2; int c = 0; if (a < 4) {c = a + b} else {c = a - b}
    /// </summary>
    void Test()
    {
        RuntimeVariableScope scope = new RuntimeVariableScope(new Dictionary<string, StatementFunction>());
        scope.InitVariable("a", TypeNotNoneName.Int);
        scope.InitVariable("b", TypeNotNoneName.Int);
        scope.InitVariable("c", TypeNotNoneName.Int);

        Statement statement = new Statement();

        ExpressionBinary expressionBinary_001 = new ExpressionBinary(BinaryOperator.assign, Variable.FromName("a").ToStatement(), Variable.FromConstInt(1).ToStatement());
        ExpressionBinary expressionBinary_002 = new ExpressionBinary(BinaryOperator.assign, Variable.FromName("b").ToStatement(), Variable.FromConstInt(2).ToStatement());
        ExpressionBinary expressionBinary_003 = new ExpressionBinary(BinaryOperator.assign, Variable.FromName("c").ToStatement(), Variable.FromConstInt(0).ToStatement());


        StatementIf statementIf = new StatementIf();
        statementIf.condition = new ExpressionBinary(BinaryOperator.equal_to, Variable.FromName("a").ToStatement(), Variable.FromConstInt(4).ToStatement());


        ExpressionBinary exressionBinary_004 = new ExpressionBinary(BinaryOperator.add, Variable.FromName("a").ToStatement(), Variable.FromName("b").ToStatement());
        ExpressionBinary exressionBinary_005 = new ExpressionBinary(BinaryOperator.assign, Variable.FromName("c").ToStatement(), exressionBinary_004);
        statementIf.trueStatement = exressionBinary_005;

        ExpressionBinary exressionBinary_006 = new ExpressionBinary(BinaryOperator.sub, Variable.FromName("a").ToStatement(), Variable.FromName("b").ToStatement());
        ExpressionBinary exressionBinary_007 = new ExpressionBinary(BinaryOperator.assign, Variable.FromName("c").ToStatement(), exressionBinary_006);
        statementIf.falseStatement = exressionBinary_007;


        statement.AddSubStatement(expressionBinary_001);
        statement.AddSubStatement(expressionBinary_002);
        statement.AddSubStatement(expressionBinary_003);
        statement.AddSubStatement(statementIf);

        statement.Execute(scope);

        var v = scope.Load("c");
    }


    /// <summary>
    /// fun abc(int a, int b)->int
    /// {
    ///     int result = 1;
    ///     for (int i = 0; i < a; i ++)
    ///     {
    ///         result = result * b
    ///         if (result > 100)
    ///         {
    ///             return result;
    ///         }
    ///     }
    ///     return -1;
    /// }
    /// int a = abc(5, 7)
    /// </summary>
    /// 

    StatementFunction CreateStatementFunction()
    {
        StatementFunction statementFunction = new StatementFunction();
        statementFunction.inParamNames.Add("a");
        statementFunction.inParamNames.Add("b");

        // int result = 1;
        statementFunction.AddSubStatement(new StatementDeclareVariable("result", TypeNotNoneName.Int));
        ExpressionBinary expressionBinary_001 = new ExpressionBinary(BinaryOperator.assign, Variable.FromName("result").ToStatement(), Variable.FromConstInt(1).ToStatement());
        statementFunction.AddSubStatement(expressionBinary_001);

        // for ()
        StatementFor statementFor = new StatementFor();
        statementFunction.AddSubStatement(statementFor);
        statementFor.for_begin_statement = new Statement(new StatementDeclareVariable("i", TypeNotNoneName.Int),
                                                            new ExpressionBinary(BinaryOperator.assign, Variable.FromName("i").ToStatement(), Variable.FromConstInt(0).ToStatement()));

        statementFor.for_step_statement = new ExpressionBinary(BinaryOperator.assign, Variable.FromName("i").ToStatement(),
                                                            new ExpressionBinary(BinaryOperator.add, Variable.FromName("i").ToStatement(), Variable.FromConstInt(1).ToStatement()));

        statementFor.for_condition_expression = new ExpressionBinary(BinaryOperator.less_than, Variable.FromName("i").ToStatement(), Variable.FromName("a").ToStatement());

        statementFor.for_body_statement.AddSubStatement(new ExpressionBinary(BinaryOperator.assign, Variable.FromName("result").ToStatement(),
                                                            new ExpressionBinary(BinaryOperator.mul, Variable.FromName("result").ToStatement(), Variable.FromName("b").ToStatement())));

        // if (result > 100)
        StatementIf statementIf = new StatementIf();
        statementFor.for_body_statement.AddSubStatement(statementIf);
        statementIf.condition = new ExpressionBinary(BinaryOperator.great_than, Variable.FromName("result").ToStatement(), Variable.FromConstInt(100).ToStatement());
        statementIf.trueStatement = Variable.FromName("result").WithFlag(ControlFlowFlag.Return).ToStatement();

        // return -1
        statementFunction.AddSubStatement(Variable.FromConstInt(-1).WithFlag(ControlFlowFlag.Return).ToStatement());
        return statementFunction;
    }
    void Test2()
    {
        RuntimeVariableScope scope = new RuntimeVariableScope(new Dictionary<string, StatementFunction>());
        scope.InitVariable("a", TypeNotNoneName.Int);
        StatementCallFunction statementCallFunction = new StatementCallFunction();
        statementCallFunction.inVariables.Add(Variable.FromConstInt(5));
        statementCallFunction.inVariables.Add(Variable.FromConstInt(7));

        statementCallFunction.statementFunction = CreateStatementFunction();
        ExpressionBinary expressionBinary = new ExpressionBinary(BinaryOperator.assign, Variable.FromName("a").ToStatement(), statementCallFunction);
        expressionBinary.Execute(scope);

        var v = scope.Load("a") as TypeInt;
        System.Diagnostics.Debug.WriteLine($"a = {v.value}");
    }

    void Test3()
    {
        Parser parser = new Parser();
        parser.UnitTest();
    }
}